package edu.hawaii.duedates;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import edu.hawaii.duedates.library.HawaiiState;
import edu.hawaii.duedates.library.UhManoa;

/**
 * Due Dates used to retrieve info on user's library books including title of books borrowed and due
 * date.
 * 
 * @author John Zhou
 * @author John Ly
 */
public final class DueDates {
  private List<BorrowedItem> itemList = new ArrayList<BorrowedItem>();

  /**
   * The main class logs into specified library and retrieves info on books.
   * 
   * @param args Four strings: uhID, uhLastName, hiStateId, hiStatePassword.
   * @throws Exception If problems occur accessing the library sites.
   */
  public static void main(String[] args) throws Exception {
    DueDates duedates = new DueDates(args);
    String toAddr = "";
    String smtpServer = "";
    boolean sendEmail = false;
    boolean console = false;
    try {
      for (int i = 0; i < args.length; i++) {
        if (args[i].equals("-wakeup")) {
          // schedules a task
          double d = 0;
          Timer timer = new Timer();
          d = Double.parseDouble(args[i + 1]);
          Calendar nextTask = Calendar.getInstance();
          nextTask.add(Calendar.MILLISECOND, (int) (d * 1000 * 60 * 60 * 24));
          timer.schedule(new Wakeup(args), nextTask.getTime(), (long) (d * 1000 * 60 * 60 * 24));
          i = i + 1;
        }
        else if (args[i].equals("-email")) {
          sendEmail = true;
          toAddr = args[i + 1];
          smtpServer = args[i + 2];
          i = i + 2;
        }
        else if (args[i].equals("-console")) {
          console = true;
        }
      }
      if (sendEmail) {
        duedates.sendEmail(duedates.getItemList(), toAddr, smtpServer);
      }
      if (console) {
        System.out.printf(duedates.printResults(duedates.getItemList()));
      }
    }
    catch (ArrayIndexOutOfBoundsException ae) {
      System.out.println("Invalid number of arguments");
    }
    catch (Exception e) {
      System.out.println("Error: " + e.getMessage());
      duedates.printResults(duedates.getItemList());
    }
  }

  /**
   * Removes any books in the list that are beyond the within period specified by user.
   * 
   * @param list The list that holds all the books.
   * @param days The number of days from today to determine the period.
   * @return If error parsing.
   */
  public List<BorrowedItem> withinNumOfDays(List<BorrowedItem> list, int days) {
    String displayFrame = "=============================================";
    Calendar dateWithin = Calendar.getInstance(Locale.US);
    dateWithin.set(Calendar.HOUR_OF_DAY, 23);
    dateWithin.set(Calendar.MINUTE, 59);
    dateWithin.set(Calendar.SECOND, 59);
    dateWithin.set(Calendar.MILLISECOND, 0);
    dateWithin.add(Calendar.DATE, days);
    BorrowedItem book = new BorrowedItem("", dateWithin, "", "");
    System.out.println();
    System.out.println(displayFrame);
    System.out.printf("Books that are due by: %s%n", book.printDueDate());
    System.out.println(displayFrame);
    for (int i = 0; i < list.size(); i++) {
      book = list.get(i);
      // if book is beyond the within period
      if (book.getDueDate().compareTo(dateWithin) > 0) {
        list.remove(i--);
      }
    }
    return list;
  }

  /**
   * Login and retrieve checked out information from the UH Library web site.
   * 
   * @param id The 8-digit UH ID number.
   * @param lastName The last name that corresponds to the UH ID number.
   * @param itemList The list to add the borrowed items to.
   * @return The list with the retrieved borrowed items added.
   * @throws Exception If error logging in to UH library.
   */
  private List<BorrowedItem> retrieveUhManoaInfo(String id, String lastName,
      List<BorrowedItem> itemList) throws Exception {
    UhManoa uhLibrary = new UhManoa();
    System.out.printf("Getting data for UH Manoa....");
    List<BorrowedItem> addedList = uhLibrary.getInfo(id, lastName, itemList);
    // getInfo adds all books checked out to itemList and returns the list
    System.out.printf("DONE!%n");
    return addedList;
  }

  /**
   * Login and retrieve checked out information from the Hawai'i State Library web site.
   * 
   * @param id The 10-digit bar code on the public library card.
   * @param password The password to the account (usually last 4 digit of phone number).
   * @param itemList The list to add the borrowed items to.
   * @return The list with the retrieved borrowed items added.
   * @throws Exception If error logging in to Hawai'i State library.
   */
  private List<BorrowedItem> retrieveHawaiiStateInfo(String id, String password,
      List<BorrowedItem> itemList) throws Exception {
    HawaiiState hiLibrary = new HawaiiState();
    System.out
        .printf("Getting data from Hawaii State Library System (this can take 1 minute)...%n");
    List<BorrowedItem> addedList = hiLibrary.getInfo(id, password, itemList);
    System.out.printf("DONE!%n");
    return addedList;
  }

  /**
   * Prints out the results stored in the list.
   * 
   * @param itemList The list containing all borrowed items that satisfy the requirements.
   * @return String containing all book information in the itemList.
   */
  public String printResults(List<BorrowedItem> itemList) {
    String output;
    if (itemList.isEmpty()) {
      return "\nNo Items Due";
    }
    else {
      String format = "%1$-14.14s | %2$-50.50s | %3$-10.10s | %4$-20.20s\n";
      output = "\n";
      output = output.concat(String.format(format, "Due Date", "Title", "Media Type", "Lender"));
      for (int j = 0; j < itemList.size(); j++) {
        output = output.concat(itemList.get(j).toString());
      }
      return output;
    }
  }

  /**
   * Creates a Mailer instance and send out an email with the list of books due.
   * 
   * @param itemList The list of BorrowedItems that are due.
   * @param toAddr The recipient of the email.
   * @param smtpServer The smtp server to use.
   * @throws Exception If error sending the email.
   */
  public void sendEmail(List<BorrowedItem> itemList, String toAddr, String smtpServer)
      throws Exception {
    Mailer mailer = new Mailer();
    mailer.send(toAddr, smtpServer, printResults(itemList));
    System.out.println("Email sent to " + toAddr);
  }

  /**
   * Get method for itemList.
   * @return List of items.
   */
  public List<BorrowedItem> getItemList () {
    return itemList;
  }
  
  /**
   * Set method for itemList.
   * @param itemList List of items.
   */
  public void setItemList (List<BorrowedItem> itemList) {
    this.itemList = itemList;
  }
  
  /**
   * Constructor for DueDates class.
   * @param args The arguments inputed into the system.
   */
  DueDates(String[] args) {
    try {
      for (int i = 0; i < args.length; i++) {
        // Check UH Manoa Library
        if (args[i].equals("-uhm")) {
          this.setItemList(retrieveUhManoaInfo(args[i + 1], args[i + 2], itemList));
          i = i + 2;
        }
        // Check the Hawaii State Library.
        else if (args[i].equals("-hsl")) {
          this.setItemList(retrieveHawaiiStateInfo(args[i + 1], args[i + 2], itemList));
          i = i + 2;
        }
        else if (args[i].equals("-sort")) {
          if (args[i + 1].equals("library")) {
            // default so just increment the index
            Collections.sort(itemList, new LenderComparator());
            i++;
          }
          else if (args[i + 1].equals("duedate")) {
            // sort by due dates
            Collections.sort(itemList);
            i++;
          }
        }
        else if (args[i].equals("-within")) {
          // output books that are due within a specified number of days
          int days = Integer.parseInt(args[i + 1]);
          if (days > 0) {
            itemList = this.withinNumOfDays(itemList, days);
          }
          i++;
        }
      }
    }
    catch (ArrayIndexOutOfBoundsException ae) {
      System.out.println("Invalid number of arguments");
    }
    catch (Exception e) {
      System.out.println("Error: " + e.getMessage());
      this.printResults(itemList);
    }
  }
}
